<template>
	<view class="component-container" v-if="visible">
		<view class="page-mask" @click="close"></view>
		<view class="content-container">
			<view class="content-title">
				<view class="content-title-left"> 日期 </view>
				<view class="content-title-right" @click="quickSelect"> {{ rightText }} </view>
			</view>
			<!-- 内容区 -->
			<view class="content">
				<view class="cal-month">
					<view @click="changeCalendarYear(-1)">
						<uni-icons type="left" size="20" color="#333"></uni-icons>
					</view>
					<view @click="changeCalendarData(-1)">
						<uni-icons type="left" size="20" color="#333"></uni-icons>
					</view>
					<view>{{ calendarMonthText }}</view>
					<view @click="changeCalendarData(1)">
						<uni-icons type="right" size="20" color="#333"></uni-icons>
					</view>
					<view @click="changeCalendarYear(1)">
						<uni-icons type="right" size="20" color="#333"></uni-icons>
					</view>
				</view>
				<view class="cal-grid">
					<view class="cal-week" v-for="week,index in weekList" :key="index">
						<view class="week-item">{{ week }}</view>
					</view>
					<view class="cal-day" v-for="day,index in dateList" :key="index">
						<view @click="selectValue(day)"
							:class="['day-item', (checkedDate.startsWith(calendarMonth)&&day==Number(checkedDate.slice(8,10))?'checked':(currDay.startsWith(calendarMonth)&&day==Number(currDay.slice(8,10))?'now':''))]">
							{{ day==0 ? '' : day }}
						</view>
					</view>
				</view>
			</view>
		</view>
	</view>
</template>

<script setup>
	import {
		ref,
		watch
	} from 'vue';

	const props = defineProps({
		/**
		 *  yyyy-MM-dd  
		 */
		modelValue: {
			type: String, // 任意类型
			default: null,
		}
	});

	const emit = defineEmits(['update:modelValue', 'change']);

	const visible = ref(false); // 控制弹窗的显示状态
	const rightText = ref('今天'); // 今天||昨天
	/**
	 * yyyy-MM-dd
	 */
	const currDay = ref(''); // 今天日期
	/**
	 * yyyy-MM
	 */
	const calendarMonth = ref(''); // 日历当前年月
	/**
	 * yyyy年MM月
	 */
	const calendarMonthText = ref(''); // 日历当前年月汉字
	/**
	 * yyyy-MM-dd
	 */
	const checkedDate = ref(props.modelValue); // 默认选中日期
	const weekList = ref(['一', '二', '三', '四', '五', '六', '日']); // 周数组
	const dateList = ref([]); // 日历数据

	// 监听 modelValue 的变化
	watch(
		[() => props.modelValue],
		([newModelValue]) => {
			checkedDate.value = newModelValue
		}
	);

	/**
	 * 数据初始化
	 */
	const initCalendarData = () => {
		currDay.value = getCurrentDate()
		// 默认选中的天
		if (!checkedDate.value || checkedDate.value.trim() == '' || checkedDate.value.trim() == 'null') {
			checkedDate.value = getCurrentDate()
		}
		// 右上角文字
		if (checkedDate.value == getCurrentDate()) {
			rightText.value = '昨天'
		} else {
			rightText.value = '今天'
		}
		// 获取日历数据
		getCalendarData(checkedDate.value)
	}

	/**
	 * 上一月、下一月
	 * @param {number} num 正数下，负数上
	 */
	const changeCalendarData = (num) => {
		let changDate = getMonthOfAS(calendarMonth.value, num)
		getCalendarData(changDate)
	}

	/**
	 * 上一年、下一年
	 * @param {number} num 正数下，负数上
	 */
	const changeCalendarYear = (num) => {
		let changDate = getYearMonthOfAS(calendarMonth.value, num)
		getCalendarData(changDate)
	}

	/**
	 * 获取某一月的日历数据
	 * @param {string} date 年月份 yyyy-MM || yyyy-MM-dd
	 */
	const getCalendarData = (date) => {
		calendarMonth.value = date.slice(0, 7)
		calendarMonthText.value = date.split('-')[0] + '年' + date.split('-')[1] + '月'
		// 月总天数
		let dayNum = getDayNumOfMonth(date)
		// 月第一天星期几下坐标
		let firstWeekIndex = getFirstDayIndexOfWeek(date)
		// 封装日历数据
		let temDateList = []
		// 日历 第一天前面补充0
		for (let i = 0; i < firstWeekIndex; i++) {
			temDateList.push(0)
		}
		for (let i = 1; i <= dayNum; i++) {
			temDateList.push(i)
		}
		dateList.value = temDateList
	}

	/**
	 * 获取当前日期 yyyy-MM-dd
	 * @return {string} yyyy-MM-dd
	 */
	const getCurrentDate = () => {
		const date = new Date();
		const year = date.getFullYear();
		const month = String(date.getMonth() + 1).padStart(2, '0');
		const day = String(date.getDate()).padStart(2, '0');
		return `${year}-${month}-${day}`;
	}

	/**
	 * 获取月的总天数
	 * @param {string} inputDate 日期 yyyy-MM || yyyy-MM-dd
	 * @return {number} 总天数
	 */
	const getDayNumOfMonth = (inputDate) => {
		const now = new Date()
		let year = now.getFullYear() // 年
		let month = now.getMonth() // getMonth() 返回的是 0-11，所以 +1
		// 如果有输出日期
		if (inputDate) {
			year = Number(inputDate.split('-')[0])
			month = Number(inputDate.split('-')[1]) - 1
		}
		// 创建一个下个月第一天的日期对象，然后减去1天，得到的就是当月的最后一天
		const lastDay = new Date(year, month + 1, 0)
		let dayNum = lastDay.getDate()
		return dayNum
	}

	/**
	 * 获取月的第一天是星期几 (对应的周数组数据下标)
	 * @param {string} inputDate 日期 yyyy-MM || yyyy-MM-dd
	 * @return {number} 日期数组下标
	 */
	const getFirstDayIndexOfWeek = (inputDate) => {
		const now = new Date()
		let year = now.getFullYear() // 年
		let month = now.getMonth() // getMonth() 返回的是 0-11，所以 +1
		// 如果有输出日期
		if (inputDate) {
			year = inputDate.split('-')[0]
			month = Number(inputDate.split('-')[1]) - 1
		}
		// 获取当月第一天
		const firstDay = new Date(year, month, 1)
		// 获取当月第一天是星期几（0-6，0是星期日）
		let week = firstDay.getDay()
		if (week == 0) {
			week = 7
		}
		// 获取日期数组下标
		let weekIndex = week - 1
		return weekIndex
	}

	/**
	 * 月份加
	 * @param {string} dataStr yyyy-MM || yyyy-MM-dd
	 * @param {number} num 正数加，负数减
	 * @returns {string} yyyy-MM
	 */
	const getMonthOfAS = (dataStr, num) => {
		// 格式化长日期 = 2025-04
		const monthStr = dataStr.slice(0, 7)
		const [year, month] = monthStr.split('-').map(Number);
		// 创建一个 Date 对象，设置为输入的年份和月份（月份从 0 开始）
		const date = new Date(year, month - 1, 1);
		// 加数量
		date.setMonth(date.getMonth() + num);
		// 格式化为 YYYY-MM 的形式
		const previousYear = date.getFullYear();
		const previousMonth = String(date.getMonth() + 1).padStart(2, '0');
		return `${previousYear}-${previousMonth}`;
	}

	/**
	 * 年份加
	 * @param {string} dataStr yyyy-MM || yyyy-MM-dd
	 * @param {number} num 正数加，负数减
	 * @returns {string} yyyy-MM
	 */
	const getYearMonthOfAS = (dataStr, num) => {
		// 格式化长日期 = 2025-04
		const monthStr = dataStr.slice(0, 7)
		const [year, month] = monthStr.split('-').map(Number);
		// 创建一个 Date 对象，设置为输入的年份和月份（月份从 0 开始）
		const date = new Date(year, month - 1, 1);
		// 加数量
		date.setFullYear(date.getFullYear() + num);
		// 格式化为 YYYY-MM 的形式
		const previousYear = date.getFullYear();
		const previousMonth = String(date.getMonth() + 1).padStart(2, '0');
		return `${previousYear}-${previousMonth}`;
	}

	/**
	 * 打开弹窗
	 */
	const open = () => {
		visible.value = true
		initCalendarData()
	};

	/**
	 * 关闭弹窗
	 */
	const close = () => {
		visible.value = false
	};

	/**
	 * 快捷选择
	 */
	const quickSelect = () => {
		let resultDate = ''
		if (rightText.value == '昨天') {
			const prevDate = new Date();
			prevDate.setDate(prevDate.getDate() - 1);

			const year = prevDate.getFullYear();
			const month = String(prevDate.getMonth() + 1).padStart(2, '0');
			const day = String(prevDate.getDate()).padStart(2, '0');
			resultDate = `${year}-${month}-${day}`
		} else if (rightText.value == '今天') {
			resultDate = getCurrentDate()
		}
		close()
		emit('update:modelValue', resultDate);
		emit('change', resultDate)
	}

	/**
	 * 选择日期
	 */
	const selectValue = (item) => {
		let curMonth = calendarMonth.value
		let formarDate = curMonth.split('-')[0] + '-' + curMonth.split('-')[1] + '-' + (item > 9 ? item : ('0' + item))

		close()
		emit('update:modelValue', formarDate);
		emit('change', formarDate)
	};

	// 暴露方法给父组件
	defineExpose({
		open,
		close
	});
</script>

<style scoped>
	.component-container {
		position: fixed;
		top: 0;
		left: 0;
		width: 100%;
		height: 100%;
		display: flex;
		justify-content: center;
		align-items: center;
		z-index: 1000;
	}

	.page-mask {
		position: absolute;
		top: 0;
		left: 0;
		width: 100%;
		height: 100%;
		background-color: rgba(0, 0, 0, 0.2);
	}

	.content-container {
		position: absolute;
		margin: auto;
		width: 520rpx;
		border-radius: 30rpx;
		padding: 50rpx 40rpx 40rpx;
		background-color: #fff;
		box-shadow: 0 0 20rpx 4rpx rgba(136, 136, 136, 0.2);
	}

	.content-title {
		margin-bottom: 10rpx;
		font-size: 28rpx;
		display: flex;
		justify-content: space-between;
		align-items: center;
	}

	.content-title-left {
		margin-left: 10rpx;
		font-size: 32rpx;
	}

	.content-title-right {
		margin-right: 10rpx;
		font-size: 28rpx;
	}

	.content {}

	.cal-month {
		padding: 30rpx 10rpx;
		display: flex;
		justify-content: space-around;
		align-items: center;
	}

	.cal-grid {
		display: grid;
		grid-template-columns: repeat(7, 1fr);
		grid-template-rows: repeat(7, 1fr);
	}

	.cal-week,
	.cal-day {
		text-align: center;
		aspect-ratio: 1;
		display: flex;
		justify-content: center;
		align-items: center;
	}

	.week-item {
		font-size: 28rpx;
		color: #666666;
	}

	.day-item {
		width: 80%;
		height: 80%;
		display: flex;
		align-items: center;
		justify-content: center;
		font-size: 28rpx;
		color: #333;
	}

	.checked {
		background-color: #FF4F80;
		color: #ffffff;
		border-radius: 50%;
	}

	.now {
		color: #FF4F80;
	}
</style>